﻿#region License
/* Copyright (C) 2009 Tim Coulter
 * 
 * This file is part of ExtremeML.
 * 
 * ExtremeML is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public
 * License, as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
*/
#endregion

using System;
using System.Drawing;
using System.Xml.Linq;
using ExtremeML.Packaging;
using ExtremeML.Sdk.Gdi;
using ExtremeML.Spreadsheet;
using ExtremeML.Spreadsheet.Address;

namespace ExtremeML.Sdk.Vml
{
	/// <summary>
	/// Implements a Vml shape for use with worksheet comments.
	/// </summary>
	internal class CommentShape : Shape
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="CommentShape"/> class.
		/// </summary>
		/// <param name="worksheet">The <see cref="WorksheetWrapper"/> that contains the worksheet targeted by the associated comment.</param>
		public CommentShape(
			WorksheetWrapper worksheet)
			: base(GetDefaultElementContent())
		{
			if (worksheet == null) throw new ArgumentNullException("worksheet");

            _worksheet = worksheet;
            ClientData = new ClientData(Element.Element(Utility.X + "ClientData"), worksheet);
            Fill = new Fill(Element.Element(Utility.V + "fill"));
            SetImagePart();
        }

		/// <summary>
		/// Initializes a new instance of the <see cref="CommentShape"/> class.
		/// </summary>
		/// <param name="element">An <see cref="XElement"/> to which this instance is bound.</param>
		/// <param name="worksheet">The <see cref="WorksheetWrapper"/> that contains the worksheet targeted by the associated comment.</param>
		/// <param name="cell">A <see cref="GridReference"/> that specifies the location of the associated cell.</param>
		public CommentShape(
			XElement element,
			WorksheetWrapper worksheet,
			GridReference cell)
			: base(element)
		{
			if (worksheet == null) throw new ArgumentNullException("worksheet");
			if (element == null) throw new ArgumentNullException("element");

		    _worksheet = worksheet;
			ClientData = new ClientData(Element.Element(Utility.X + "ClientData"), worksheet, cell);
            Fill = new Fill(Element.Element(Utility.V + "fill"));
            SetImagePart();
		}

	    private readonly WorksheetWrapper _worksheet;
	    private ImagePartWrapper _imagePart;

        /// <summary>
        /// Gets the contained <see cref="Fill"/> instance.
        /// </summary>
        public Fill Fill { get; private set; }

		/// <summary>
		/// Gets the contained <see cref="ClientData"/> instance.
		/// </summary>
		public ClientData ClientData { get; private set; }

		/// <summary>
		/// Removes this instance from its containing <see cref="VmlDrawing"/>.
		/// </summary>
		public void Remove()
		{
			Element.Remove();			
		}

		/// <summary>
		/// Sets the properties of this element and regenerates the underlying Xml.
		/// </summary>
		/// <param name="properties">The properties of the associated shape.</param>
		public void Configure(
			ShapeProperties properties)
		{
			if (properties == null) throw new ArgumentNullException("properties");

			ClientData.Configure(properties);
		}

        /// <summary>
        /// Returns the fill image of this element.
        /// </summary>
        /// <returns>A <see cref="Bitmap"/> retrieved from the associated image part.</returns>
        public Bitmap GetImage()
        {
            return _imagePart == null ? null : _imagePart.GetImage();
        }
        
        /// <summary>
        /// Sets the fill image of this element and regenerates the underlying Xml.
        /// </summary>
        /// <param name="image">A <see cref="Bitmap"/> to be used as the fill image.</param>
        /// <param name="width">A nullable <see cref="int"/> that specifies the rendered image width.</param>
        /// <param name="height">A nullable <see cref="int"/> that specifies the rendered image height.</param>
        public void SetImage(
            Bitmap image,
            int? width,
            int? height)
        {
            if (_imagePart != null)
            {
                _imagePart.Remove();
                Fill.SetImage(null);
                _imagePart = null;
            }

            if (image != null)
            {
                _imagePart = _worksheet.WorksheetPart.GetCommentDrawingPart().ImageParts.Add(image);
                Fill.SetImage(_imagePart.Id);
                Configure(new ShapeProperties(null, null, Imaging.GetScaledImageSize(image, width, height)));
            }
        }

        /// <summary>
        /// Establishes a reference to the associated image part.
        /// </summary>
        private void SetImagePart()
        {
            var id = Fill.GetImagePartId();
            _imagePart = id == null ? null : _worksheet.WorksheetPart.GetCommentDrawingPart().ImageParts.Find(id);
        }

		/// <summary>
		/// Returns an <see cref="XElement"/> containing the default content for this class.
		/// </summary>
		private static XElement GetDefaultElementContent()
		{
			return new XElement(Utility.V + "shape",
				new XAttribute("id", SpreadsheetDocumentWrapper.GetUniqueIdString()),
				new XAttribute("type", "#" + CommentShapeType.ShapeTypeId),
				new XAttribute("style", "position:absolute; visibility:hidden;"),
				new XAttribute("fillcolor", "#ffffe1"),
				new XAttribute(Utility.O + "insetmode", "auto"),
				new XElement(Utility.V + "fill",
					new XAttribute("color2", "#ffffe1")),
				new XElement(Utility.V + "shadow",
					new XAttribute("on", "t"),
					new XAttribute("color", "black"),
					new XAttribute("obscured", "t")),
				new XElement(Utility.V + "path",
					new XAttribute("connecttype", "none")),
				new XElement(Utility.V + "textbox",
					new XAttribute("style", "mso-direction-alt:auto"),
					new XElement("div",
						new XAttribute("style", "text-align:left"))),
				new XElement(Utility.X + "ClientData",
					new XAttribute("ObjectType", "Note"),
					new XElement(Utility.X + "MoveWithCells"),
					new XElement(Utility.X + "SizeWithCells"),
					new XElement(Utility.X + "Anchor", "0, 0, 0, 0, 0, 0, 0, 0"),
					new XElement(Utility.X + "AutoFill", false),
					new XElement(Utility.X + "Row", 0),
					new XElement(Utility.X + "Column", 0)));
		}
	}
}